package handler

import (
	"context"
	"errors"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"pm_back_server/project-server/global"
	"pm_back_server/project-server/model"
	"pm_back_server/project-server/proto"
	"pm_back_server/project-server/utils"
)

func HandleTaskModelToResponse(taskMode *model.Task) *proto.TaskResponseInfo {
	return &proto.TaskResponseInfo{
		Id:          uint64(taskMode.ID),
		Name:        taskMode.Name,
		Grade:       taskMode.Grade,
		Status:      taskMode.Status,
		OwnerId:     taskMode.OwnerId,
		IterationId: taskMode.IterationId,
		ProjectId:   taskMode.ProjectId,
		GroupId:     taskMode.GroupId,
	}
}

// CreateTask /* 创建任务
func (p *ProjectServer) CreateTask(ctx context.Context, req *proto.CreateTaskInfo) (*proto.TaskResponseInfo, error) {
	errLogger := utils.NewErrorLogger("CreateTask")
	var iteration model.Iteration
	result := global.DB.First(&iteration, req.IterationId)
	if result.RowsAffected == 0 {
		errLogger("查询", "迭代", "目标迭代不存在")
		return nil, status.Errorf(codes.NotFound, IterationNotFoundStr)
	}
	// 查询团队是否存在
	if !CheckGroupExist(req.GroupId) {
		errLogger("查询", "团队", "目标团队不存在")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}
	// 查询用户是否具有创建权限
	if !CheckUserExistInGroup(req.GroupId, req.CreatorId) || req.GroupId != iteration.GroupId {
		errLogger("校验", "权限", "用户不具有权限")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}

	task := model.Task{
		Name:        req.Name,
		Grade:       req.Grade,
		Status:      req.Status,
		OwnerId:     req.OwnerId,
		CreatorId:   req.CreatorId,
		IterationId: req.IterationId,
		ProjectId:   iteration.ProjectId,
		GroupId:     req.GroupId,
	}
	result = global.DB.Create(&task)
	if result.Error != nil {
		errLogger("创建", "任务", "创建任务失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return HandleTaskModelToResponse(&task), nil
}

// GetTaskById /* 通过任务ID查询任务
func (p *ProjectServer) GetTaskById(ctx context.Context, req *proto.TaskIdInfo) (*proto.TaskResponseInfo, error) {
	errLogger := utils.NewErrorLogger("GetTaskById")
	var task model.Task
	result := global.DB.First(&task, req.Id)
	if result.RowsAffected == 0 {
		errLogger("查询", "任务", "目标任务不存在")
		return nil, status.Errorf(codes.NotFound, TaskNotFoundStr)
	}

	return HandleTaskModelToResponse(&task), nil
}

// GetTaskListByIterationId /* 通过迭代ID查询任务列表
func (p *ProjectServer) GetTaskListByIterationId(ctx context.Context, req *proto.IterationIdInfo) (*proto.TaskListResponseInfo, error) {
	var iteration model.Iteration
	result := global.DB.First(&iteration, req.Id)
	if result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, IterationNotFoundStr)
	}

	var tasks []model.Task
	result = global.DB.Model(&model.Task{}).Where("iteration_id = ?", req.Id).Find(&tasks)

	rsp := &proto.TaskListResponseInfo{}
	for _, task := range tasks {
		rsp.TaskList = append(rsp.TaskList, HandleTaskModelToResponse(&task))
	}

	return rsp, nil
}

// UpdateTask /* 更新任务
func (p *ProjectServer) UpdateTask(ctx context.Context, req *proto.UpdateTaskInfo) (*empty.Empty, error) {
	errLogger := utils.NewErrorLogger("UpdateTask")
	var task model.Task
	result := global.DB.First(&task, req.Id)
	if result.RowsAffected == 0 {
		errLogger("查询", "任务", "目标任务不存在")
		return nil, status.Errorf(codes.NotFound, TaskNotFoundStr)
	}
	// 当用户存在团队中，并且目标任务的团队和传入的团队为同一个时，跳过判断
	if !CheckUserExistInGroup(req.GroupId, req.UserId) || task.GroupId != req.GroupId {
		errLogger("校验", "权限", "用户不具有权限")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}

	task.Name = req.Name
	task.Grade = req.Grade
	task.Status = req.Status
	task.OwnerId = req.OwnerId

	result = global.DB.Save(&task)
	if result.Error != nil {
		errLogger("更新", "任务", "更新目标任务失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// DeleteTask /* 删除任务
func (p *ProjectServer) DeleteTask(ctx context.Context, req *proto.DeleteTaskInfo) (*empty.Empty, error) {
	errLogger := utils.NewErrorLogger("DeleteTask")
	var task model.Task
	result := global.DB.First(&task, req.Id)
	if result.RowsAffected == 0 {
		errLogger("查询", "任务", "目标任务不存在")
		return nil, status.Errorf(codes.NotFound, TaskNotFoundStr)
	}
	// 当用户存在团队中，并且目标任务的团队和传入的团队为同一个时，跳过判断
	if !CheckUserExistInGroup(req.GroupId, req.UserId) || task.GroupId != req.GroupId {
		errLogger("校验", "权限", "用户不具有权限")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}

	result = global.DB.Model(&model.Task{}).Delete(&task, req.Id)
	if result.Error != nil {
		errLogger("删除", "任务", "删除目标任务失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// DeleteTaskByGroupId /* 通过团队ID删除任务
func (p *ProjectServer) DeleteTaskByGroupId(req *proto.GroupIdInfo) error {
	if !CheckGroupExist(req.Id) {
		zap.S().Errorw("[DeleteTaskById] 查询 [团队] 失败")
		return errors.New("删除任务失败")
	}

	var tasks []model.Task
	result := global.DB.Model(&model.Task{}).Where("group_id = ?", req.Id).Delete(&tasks)
	if result.Error != nil {
		zap.S().Errorw("[DeleteTaskById] 删除 [任务] 失败")
		return errors.New("删除任务失败")
	}
	return nil
}

// DeleteTaskByProjectId /* 通过项目ID删除任务
func (p *ProjectServer) DeleteTaskByProjectId(req *proto.ProjectIdInfo) error {
	if !CheckProjectExist(req.Id) {
		zap.S().Errorw("[DeleteTaskByProjectId] 查询 [项目] 失败")
		return errors.New("删除任务失败")
	}
	var tasks []model.Task
	result := global.DB.Model(&model.Task{}).Where("project_id = ?", req.Id).Delete(&tasks)
	if result.Error != nil {
		zap.S().Errorw("[DeleteTaskByProjectId] 删除 [任务] 失败")
		return errors.New("删除任务失败")
	}
	return nil
}

// DeleteTaskByIterationId /* 通过迭代ID删除任务
func (p *ProjectServer) DeleteTaskByIterationId(req *proto.IterationIdInfo) error {
	if !CheckIterationExist(req.Id) {
		zap.S().Errorw("[DeleteTaskByIterationId] 查询 [迭代] 失败")
		return errors.New("删除任务失败")
	}
	var tasks []model.Task
	result := global.DB.Model(&model.Task{}).Where("iteration_id = ?", req.Id).Delete(&tasks)
	if result.Error != nil {
		zap.S().Errorw("[DeleteTaskByIterationId] 删除 [任务] 失败")
		return errors.New("删除任务失败")
	}
	return nil
}
